# -*- coding: utf-8 -*-
# owner: shenyi
# file: src/providers/aliyun/ecs.py

from typing import Optional, List
from abc import ABC

from src.providers.base import BaseProvider
from src.models.instance import (
    CreateInstanceRequest,
    DeleteInstanceRequest,
    InstanceTypeRequest,
    QueryInstanceRequest,
    AvailableInstanceTypeRequest,
)
from src.models.responses import (
    CreateResponse,
    DeleteResponse,
    InstanceTypeResponse,
    AvailableZonesInstanceTypeResponse,
    InstanceType as ResponseInstanceType,
    AvailableZoneInstanceType,
    InstanceListResponse,
    Instance as ResponseInstance,
)
from src.core import logger
from src.strategies import ExcludeInstanceFamilyStrategy

from .client import Client
from alibabacloud_ecs20140526 import models as ecs_models
from alibabacloud_tea_util import models as util_models


class Ecs(BaseProvider):
    """
    阿里云 ECS 实现类
    """

    def __init__(self, **config):
        super().__init__(**config)
        # 可选：将 client 作为实例属性，支持依赖注入（便于 mock 测试）
        self._client = config.get("client") or Client.ecs_client()

    async def create_instance(self, request: CreateInstanceRequest) -> CreateResponse:
        """
        创建 ECS 实例

        Docs: https://next.api.aliyun.com/api/Ecs/2014-05-26/RunInstances
        """
        disks: List[ecs_models.RunInstancesRequestDataDisk] = []

        if request.data_disk:
            for disk in request.data_disk:
                data_disk = ecs_models.RunInstancesRequestDataDisk(
                    size=disk["size"],
                    category=disk["category"],  # e.g., cloud_essd
                )
                disks.append(data_disk)

        run_request = ecs_models.RunInstancesRequest(
            host_name=request.host_name,
            region_id=self._client._region_id,
            image_id=request.image_id,
            instance_type=request.instance_type,
            internet_max_bandwidth_out=request.internet_max_bandwidth_out,
            data_disk=disks,
            launch_template_id=request.launch_template_id,
            launch_template_version=int(request.launch_template_version) if request.launch_template_version else None,
        )

        runtime = util_models.RuntimeOptions()
        try:
            response = await self._client.run_instances_with_options_async(run_request, runtime)
            instance_ids = response.body.instance_id_sets.instance_id_set or []
            return CreateResponse(instance_ids=instance_ids)
        except Exception as e:
            error_msg = str(e)
            logger.error(f"Failed to create ECS instance: {error_msg}")
            return CreateResponse(status_code=400, message=error_msg)

    async def delete_instance(self, request: DeleteInstanceRequest) -> DeleteResponse:
        """
        删除 ECS 实例

        Docs: https://next.api.aliyun.com/api/Ecs/2014-05-26/DeleteInstance
        """
        delete_request = ecs_models.DeleteInstanceRequest(
            instance_id=request.instance_id,
            force=True,
        )
        runtime = util_models.RuntimeOptions()
        try:
            await self._client.delete_instance_with_options_async(delete_request, runtime)
            return DeleteResponse(status_code=200, message="success")
        except Exception as e:
            error_msg = str(e)
            logger.error(f"Failed to delete ECS instance {request.instance_id}: {error_msg}")
            return DeleteResponse(status_code=400, message=error_msg)

    async def list_instance_types(self, request: InstanceTypeRequest) -> InstanceTypeResponse:
        """
        查询实例规格列表

        Docs: https://next.api.aliyun.com/api/Ecs/2014-05-26/DescribeInstanceTypes
        """
        families_list = (
            request.instance_type_families.split(",") if request.instance_type_families else None
        )

        describe_request = ecs_models.DescribeInstanceTypesRequest(
            cpu_architecture=request.cpu_architecture,
            instance_category=request.instance_category,
            instance_type_family=families_list,
            minimum_cpu_core_count=request.mini_cpu_core_count,
            minimum_memory_size=request.mini_memory_size,
        )

        runtime = util_models.RuntimeOptions()
        try:
            response = await self._client.describe_instance_types_with_options_async(describe_request, runtime)
            instance_types = response.body.instance_types.instance_type or []

            filtered_specs = []
            for it in instance_types:
                # 应用排除策略
                if request.exclude_families and ExcludeInstanceFamilyStrategy.exclude(
                    it.instance_type_id, request.exclude_families
                ):
                    continue

                filtered_specs.append(
                    ResponseInstanceType(
                        memory_size=it.memory_size,
                        instance_type_id=it.instance_type_id,
                        cpu_core_count=it.cpu_core_count,
                        cpu_architecture=it.cpu_architecture,
                    )
                )

            return InstanceTypeResponse(
                status_code=200,
                message="success",
                instance_spec=filtered_specs,
            )
        except Exception as e:
            error_msg = str(e)
            logger.error(f"Failed to list ECS instance types: {error_msg}")
            return InstanceTypeResponse(
                status_code=400,
                message=error_msg,
                instance_spec=[],
            )

    async def list_available_instance_types(
        self, request: AvailableInstanceTypeRequest
    ) -> AvailableZonesInstanceTypeResponse:
        """
        查询可用区中可用的实例规格

        Docs: https://next.api.aliyun.com/api/Ecs/2014-05-26/DescribeAvailableResource
        """
        describe_request = ecs_models.DescribeAvailableResourceRequest(
            region_id=self._client._region_id,
            destination_resource="InstanceType",
            instance_charge_type="PostPaid",
            zone_id=request.zone_id,
            system_disk_category=request.disk_category,
            data_disk_category=request.disk_category,
        )

        runtime = util_models.RuntimeOptions()
        try:
            response = await self._client.describe_available_resource_with_options_async(describe_request, runtime)
            zones = response.body.available_zones.available_zone if response.body.available_zones else []

            result = []
            for zone in zones:
                zone_id = zone.zone_id
                for resource in zone.available_resources.available_resource:
                    for supported in resource.supported_resources.supported_resource:
                        result.append(
                            AvailableZoneInstanceType(
                                available=supported.status == "Available",
                                instance_type_id=supported.value,
                                zone_id=zone_id,
                            )
                        )

            return AvailableZonesInstanceTypeResponse(
                status_code=200,
                message="success",
                available_zone=result,
            )
        except Exception as e:
            error_msg = str(e)
            logger.error(f"Failed to list available ECS instance types: {error_msg}")
            return AvailableZonesInstanceTypeResponse(
                status_code=400,
                message=error_msg,
                available_zone=[],
            )
            
    async def list_instances(self, request: QueryInstanceRequest) -> InstanceListResponse:
        """
        查询 ECS 实例列表，支持按实例 ID 或实例名称过滤。

        Docs: https://next.api.aliyun.com/api/Ecs/2014-05-26/DescribeInstances
        """
        # 构建 InstanceId 列表（阿里云 SDK 要求传 List[str]）
        instance_ids = request.instance_ids or []

        # 构建 Tag 过滤或 InstanceName 过滤
        # 阿里云中 InstanceName 存储在 Tag 中（Key=Name）或直接通过 instance_name 参数？
        # 实际上，DescribeInstances 支持 InstanceName 作为参数（部分地域支持）
        # 更可靠的方式：使用 InstanceIds 或通过 Tag 过滤，但为简化，我们用 InstanceName 参数（官方支持）

        describe_request = ecs_models.DescribeInstancesRequest(
            region_id=self._client._region_id,
            zone_id=request.zone_id,
            instance_ids=instance_ids if instance_ids else None,
            instance_name=request.instance_name,  # 阿里云 API 支持此字段（模糊匹配）
            max_results=100,  # 可根据需要分页
        )

        runtime = util_models.RuntimeOptions()
        try:
            response = await self._client.describe_instances_with_options_async(describe_request, runtime)
            instances = response.body.instances.instance if response.body.instances else []

            instance_list = []
            for ins in instances:
                # 阿里云中 public_ip 可能在 EipAddress 或 PublicIpAddress 中
                public_ip = None
                if ins.eip_address and ins.eip_address.ip_address:
                    public_ip = ins.eip_address.ip_address
                elif ins.public_ip_address and ins.public_ip_address.ip_address:
                    public_ip = ins.public_ip_address.ip_address[0] if ins.public_ip_address.ip_address else None

                private_ip = (
                    ins.vpc_attributes.private_ip_address.ip_address[0]
                    if ins.vpc_attributes and ins.vpc_attributes.private_ip_address and ins.vpc_attributes.private_ip_address.ip_address
                    else None
                )

                instance_list.append(
                    ResponseInstance(
                        instance_id=ins.instance_id,
                        name=ins.instance_name,
                        instance_type_id=ins.instance_type,
                        status=ins.status,
                        region_id=ins.region_id,
                        zone_id=ins.zone_id,
                        private_ip=private_ip,
                        public_ip=public_ip,
                        image_id=ins.image_id,
                        vpc_id=ins.vpc_attributes.vpc_id if ins.vpc_attributes else None,
                        subnet_id=ins.vpc_attributes.vswitch_id if ins.vpc_attributes else None,
                        created_at=ins.creation_time,  # 阿里云返回格式如 "2023-01-01T12:00Z"
                        provider="aliyun",
                    )
                )

            return InstanceListResponse(
                status_code=200,
                message="success",
                instances=instance_list,
            )

        except Exception as e:
            error_msg = str(e)
            logger.error(f"Failed to list ECS instances: {error_msg}")
            return InstanceListResponse(
                status_code=400,
                message=error_msg,
                instances=[],
            )